//
// Created by gj on 16-2-18.
//

#ifndef ALLUTILS_CSHAREDPOINTER_H
#define ALLUTILS_CSHAREDPOINTER_H

#include "PointerDeleter.h"
#include "PointerCounter.h"

/**
 * 智能指针类，用来统一管理指针的内存和浅copy问题使指针可以在生命周期结束后自动释放
 * 类似与JAVA的类的传递方式，拥有一个引用计数器当这个指针不再被引用时自动释放
 * 当对象创建时，引用计数为1，执行例如a=b的操作则引用计数为2，a与b指向同一块地址
 * 如果想深copy，需要自己实现相应的copy构造函数，然后执行a=new T(*b); 此时a与b引用计数均为1，分别为两块内存
 * 这个类的所有操作方式和指针时完全一样的，想要调用类的成员函数void fun();则a->fun();即可
 *
 * 注意! 避免循环引用，这个类仅仅用来封装简单的指针管理，无法处理对于 A->B B->A 的问题，相互包含的关系会导致内存泄漏！！！
 * 注意! 不支持多线程操作
 * 注意! 不要让两个不同的智能指针持有同一个指针变量
 */
template<class T, class Dealloc = DefMemDelete<T *> >
class SharePointer {
public:
    // 用一个野指针构造智能指针，这个指针如果在外面释放了一定会引起崩溃
    SharePointer(T *ptr) //
            : LOG_INIT_NAME_DEBUG("SharePointer")
            data(ptr) {
        LOG_W_FUNC("Share pointer from T*")
    }

    SharePointer(SharePointer &sp) //
            : LOG_INIT_NAME_DEBUG("SharePointer")
            data(NULL) {
        _copy(sp);
    }

    T *operator->() {
        return data;
    }

    const T *operator->() const {
        return data;
    }

    T &operator*() {
        return (*data);
    }

    const T &operator*() const {
        return (*data);
    }

    /**
     * 获取指针实体
     * 注意不要在外面释放了这个指针
     */
    T *getPointer() {
        return data;
    }

    SharePointer &operator=(SharePointer &sp) {
        _copy(sp);
        return (*this);
    }

    bool isNull() const {
        return data == NULL;
    }

    virtual ~SharePointer() {
        _clear();
    }

protected:
    LOG_CREATE_DEBUG
    // 指向实际的数据
    T *data;
    // 指针计数
    PointerCounter counter;
    // 内存释放器
    Dealloc relloc;

    void _clear() {
        if (counter.decCount() == 1) {
            _delete();
        }
        LOG_I_FUNC("Share pointer --> %p", data)
    }

    void _copy(SharePointer &sp) {
        if (counter.copy(sp.counter) == 1) {
            _delete();
        }
        data = sp.data;
        LOG_I_FUNC("--> Share pointer: %p, %d", data, counter.getCount())
    }

    void _delete() {
        if (data != NULL) {
            relloc(data);
        }
    }
};

// --------------------------------------------- unit test --------------------------------------------------
#ifdef FLAG_UNIT_TESTING

void share_pointer_unit_testing();

#endif

#endif //ALLUTILS_CSHAREDPOINTER_H
